
#include <QCoreApplication>
#include <QHttpMultiPart>
#include <QFile>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonParseError>
#include <QJsonObject>

#include "upload.h"

Upload::Upload(QObject *parent) : QObject(parent)
{
    this->init();
}

Upload::~Upload()
{
    this->filenames.clear();
    delete this->settings;
    delete this->netManager;
    delete this->baseRequest;
}

void Upload::reset()
{
    this->filenames.clear();
    this->uploadDir = "";
    qDebug() << "Upload::" << __FUNCTION__ << "Done.";
}

void Upload::setFilenames(QStringList filenames)
{
    qDebug() << "Upload::" << __FUNCTION__ << "file list:";
    qDebug().noquote() << filenames;
    this->filenames.clear();
    this->filenames = filenames;
}

void Upload::setUploadDir(QString uploadDir)
{
    qDebug() << "Upload::" << __FUNCTION__ << uploadDir;
    this->uploadDir = uploadDir;
}

Upload::Status Upload::startUpload()
{
    this->name = this->settings->value(USER_NAME).toString();
    this->phpSessionID = this->settings->value(USER_PHPSESSID).toString();
    if(this->uploadDir.length() == 0) { return INVALID_UPLOAD_DIR; }
    if(this->name.length() == 0) { return INVALID_NAME; }
    if(this->phpSessionID.length() == 0) { return INVALID_PHPSESSID; }
    qDebug() << "Upload::" << __FUNCTION__;

    /* start upload */
    this->uploading = true;
    /* http://filegeli.timechicken.cc/index.php?explorer/fileUpload&path=%2F */
    this->uploading = true;
    QString url = QString("%1/index.php?explorer/fileUpload&path=%2")
            .arg(this->settings->value(USER_WEB_URL).toString())
            .arg(this->uploadDir);
    QNetworkRequest req = *(this->baseRequest);
    req.setUrl(url);
    qDebug() << "Upload::" << __FUNCTION__ << "URL:" << url;

    req.setRawHeader("Cookie", QString("PHPSESSID=%1; secros_user_language=zh_CN; secros_name=%2")
                         .arg(this->phpSessionID)
                         .arg(this->name)
                         .toUtf8());
    qDebug() << "Print the parameters of the request header:";
    QList<QByteArray> requestHeaderList = baseRequest->rawHeaderList();
    for(int i = 0; i < requestHeaderList.size(); i++) {
        qDebug().noquote() << requestHeaderList.at(i) << ":" << baseRequest->rawHeader(requestHeaderList.at(i));
    }

    /* 此请求与浏览器请求body不同，需要用边界字符串上报文件名，否则服务器会返回文件类型错误的消息。*/
    QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
    for(int i = 0; i < this->filenames.size(); i++) {
        QHttpPart filepart;
        QFile *file = new QFile(this->filenames.at(i));
        if(!file->open(QIODevice::ReadOnly)) {
            qDebug() << "Upload::" << __FUNCTION__ <<
                        QString("open '%1' error:%2")
                        .arg(this->filenames.at(i))
                        .arg(file->errorString());
            delete file;
            return UNDEFINED_ERROR;
        }
        filepart.setBodyDevice(file);
        file->setParent(multiPart);
        multiPart->append(filepart);
    }

    this->netManager->post(req, multiPart);

    return NO_ERROR;
}

void Upload::uploadResponse(QNetworkReply *reply)
{
    qDebug() << __FUNCTION__;
    this->uploading = false;
    /* 过滤请求错误 */
    if(reply->error() != QNetworkReply::NoError) {
        emit finished(RESPONSE_ERROR, reply->errorString());
        return ;
    }

    /* 判断响应数据 */
    QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
    /* 如果解析响应状态码错误或者状态码!=200 */
    qDebug("%s Response statusCode:%d", __FUNCTION__, statusCode.toInt());
    if(!statusCode.isValid() || statusCode.toInt() != 200) {
        QVariant reason =  reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute);
        if(reason.isValid())
            emit finished(RESPONSE_ERROR, reason.toString());
        else
            emit finished(RESPONSE_ERROR, QString("%1 Unknown response error").arg(__FUNCTION__));
        return ;
    }

    // print response data
    QByteArray jsonByteArray = reply->readAll();

    QJsonParseError jsonParseError;
    QJsonObject replyJsonObj = QJsonDocument::fromJson(jsonByteArray, &jsonParseError).object();
    if(jsonParseError.error != QJsonParseError::NoError) {
        qDebug() << "Response Data:";
        qDebug().noquote() << jsonByteArray;
        qDebug() << "Upload::" << __FUNCTION__ << "json parse error:" << jsonParseError.errorString();
        emit finished(JSON_ERROR, "Json parse error:" + jsonParseError.errorString());
        return ;
    }
    qDebug().noquote() << "Json Parse Done Data:\n" <<
                          QJsonDocument::fromJson(jsonByteArray, &jsonParseError)
                          .toJson(QJsonDocument::Indented);
    bool code = replyJsonObj.value("code").toBool();
    double user_time = replyJsonObj.value("user_time").toDouble();
    QString data = replyJsonObj.value("data").toString();
    QString info = replyJsonObj.value("info").toString();
    emit finished(code?NO_ERROR:RESPONSE_ERROR,
                  QString("user_time:%1\ndata:%2\ninfo:%3")
                      .arg(user_time).arg(data).arg(info));
}

Upload::Status Upload::init()
{
    /* init config file info */
    this->settings = new ConfigFile(QCoreApplication::applicationDirPath() + "/" + DEFAULT_FILENAME);

    /* init network env */
    this->uploading = false;
    this->netManager = new QNetworkAccessManager();
    connect(this->netManager,
            &QNetworkAccessManager::finished,
            this,
            &Upload::uploadResponse);
    this->baseRequest = new QNetworkRequest();
    baseRequest->setRawHeader("Cookie", QString("PHPSESSID=%1; secros_user_language=zh_CN; secros_name=%2")
                         .arg(settings->value(USER_PHPSESSID).toString())
                         .arg(settings->value(USER_NAME).toString())
                         .toUtf8());
    baseRequest->setHeader(QNetworkRequest::UserAgentHeader, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                                                        "AppleWebKit/537.36 (KHTML, like Gecko) Chrome"
                                                        "/104.0.0.0 Safari/537.36");
    baseRequest->setRawHeader("Host", settings->value(USER_WEB_URL).toString().mid(7).toUtf8());
    baseRequest->setRawHeader("Referer", QString("%1/index.php")
                         .arg(settings->value(USER_WEB_URL).toString()).toUtf8());

    QList<QByteArray> requestHeaderList = baseRequest->rawHeaderList();
    qDebug() << "Print the parameters of the request header:";
    for(int i = 0; i < requestHeaderList.size(); i++) {
        qDebug().noquote() << requestHeaderList.at(i) << ":" << baseRequest->rawHeader(requestHeaderList.at(i));
    }
    return NO_ERROR;
}
